#include "ShaderSystem.h"
#include "Shader.h"
#include "../Common/ZException.h"

#ifdef RENDER_OPENGL

GLOBAL_NAMESPACE_BEGIN

template<> ShaderSystem* Singleton<ShaderSystem>::singleton_ = 0;

ShaderSystem::ShaderSystem()
    : currentProgram_(-1)
    , currentVSShader_(-1)
    , currentFSShader_(-1)
    , currentGSShader_(-1)
{
}

ShaderSystem::~ShaderSystem()
{
    destroy();
}

void ShaderSystem::destroy()
{
    for (size_t i = 0; i < programs_.size(); i++)
    {
        if (programs_[i])
            delete programs_[i];
    }
    programs_.clear();
    
    for (int i = 2; i < shaders_.size(); i++)
    {
        if (shaders_[i])
            delete shaders_[i];
    }
    shaders_.clear();
}

void ShaderSystem::init()
{
    addShader(GLShader::getDefaultShader(SHADER_GL_Vertex));
    addShader(GLShader::getDefaultShader(SHADER_GL_Fragment));
}

void ShaderSystem::addShader(GLShader* shader)
{
    if (shader==NULL)
        return;
    shaders_.push_back(shader);
    switch(shader->getShaderType())
    {
    case SHADER_GL_Vertex:
        currentVSShader_ = shaders_.size()-1;
        break;
    case SHADER_GL_Fragment:
        currentFSShader_ = shaders_.size()-1;
        break;
    case SHADER_GL_Geometry:
        currentGSShader_ = shaders_.size()-1;
        break;
    }
}

QGLShaderProgram* ShaderSystem::createProgram()
{
    if (currentFSShader_<0 || currentFSShader_>=shaders_.size()
        || currentVSShader_<0 || currentVSShader_>=shaders_.size())
        return NULL;
    QGLShaderProgram* sp = new QGLShaderProgram;
    //sp->addShader(shaders_[currentVSShader_]->getShader());
    //sp->addShader(shaders_[currentFSShader_]->getShader());
    //sp->bindAttributeLocation("a_Position", 0);
    //sp->bindAttributeLocation("a_Color", 1);
    //sp->link();

    return sp;
}

QGLShaderProgram* ShaderSystem::getCurrentShaderProgram()
{
    if ( currentProgram_<0 || currentProgram_>=programs_.size() )
        return NULL;

    return programs_[currentProgram_];
}

void ShaderSystem::refresh()
{

}

void ShaderSystem::bind(QWidget* parent)
{

}

GLShader* ShaderSystem::createShader(const char* shaderType, const char* shaderName, const char* shaderFile)
{
    GLShader* shader = NULL;
    GLShaderType type;
    if (strcmp(shaderType, "VertexShader")==0)
        type = SHADER_GL_Vertex;
    else if (strcmp(shaderType, "FragmentShader")==0)
        type = SHADER_GL_Fragment;
    else if (strcmp(shaderType, "GeometryShader")==0)
        type = SHADER_GL_Geometry;
    else
        type = SHADER_UNDEFINED;

    if (type==SHADER_UNDEFINED)
        return NULL;

    shader = new GLShader(type, shaderFile, shaderName);
    addShader(shader);
    //shaders_.push_back(shader);
    //switch(type)
    //{
    //case SHADER_GL_Vertex:
    //    currentVSShader_ = shaders_.size()-1;
    //    break;
    //case SHADER_GL_Fragment:
    //    currentFSShader_ = shaders_.size()-1;
    //    break;
    //case SHADER_GL_Geometry:
    //    currentGSShader_ = shaders_.size()-1;
    //    break;
    //}
    return shader;
}

GLOBAL_NAMESPACE_END

#endif
